/**
 * @author liangxi
 * @since 2024/4/10
 */

#ifndef DESIGNPATTERN_GUMBALLMACHINE_H
#define DESIGNPATTERN_GUMBALLMACHINE_H

#include <memory>
#include "State.h"
#include "impl/HasQuarterState.h"
#include "impl/NoQuarterState.h"
#include "impl/SoldOutState.h"
#include "impl/SoldState.h"
#include "impl/WinnerState.h"

class GumballMachine {

public:
    explicit GumballMachine(int count) : mCount(count) {
        hasQuarterState = std::make_shared<HasQuarterState>();
        {
            auto tmp = std::dynamic_pointer_cast<HasQuarterState>(hasQuarterState);
            if (tmp)
                tmp->setMGumballMachine(this);
        }

        soldOutState = std::make_shared<SoldOutState>();
        {
            auto tmp = std::dynamic_pointer_cast<SoldOutState>(soldOutState);
            if (tmp)
                tmp->setMGumballMachine(this);
        }

        soldState = std::make_shared<SoldState>();
        {
            auto tmp = std::dynamic_pointer_cast<SoldState>(soldState);
            if (tmp)
                tmp->setMGumballMachine(this);
        }

        noQuarterState = std::make_shared<NoQuarterState>();
        {
            auto tmp = std::dynamic_pointer_cast<NoQuarterState>(noQuarterState);
            if (tmp)
                tmp->setMGumballMachine(this);
        }

        winnerState = std::make_shared<WinnerState>();
        {
            auto tmp = std::dynamic_pointer_cast<WinnerState>(winnerState);
            if (tmp)
                tmp->setMGumballMachine(this);
        }

        if (mCount > 0)
            mState = noQuarterState;
    }

    void insertQuarter() {
        mState->insertQuarter();
    }

    void ejectQuarter() {
        mState->ejectQuarter();
    }

    void turnCrank() {
        mState->turnCrank();
        mState->dispense();
    }

    void releaseBall() {
        std::cout << "A gumball comes rolling out the slot...\n";
        if (0 != mCount)
            mCount = mCount - 1;
    }

    std::string toString() const {
        std::string res;
        res += "Inventory: " + std::to_string(mCount) + "gumballs";
        return res;
    }

    int getMCount() const { return mCount; }

    void setState(const std::shared_ptr<State> &state) {
        GumballMachine::mState = state;
    }

    const std::shared_ptr<State> &getHasQuarterState() const { return hasQuarterState; }

    const std::shared_ptr<State> &getSoldOutState() const { return soldOutState; }

    const std::shared_ptr<State> &getSoldState() const { return soldState; }

    const std::shared_ptr<State> &getNoQuarterState() const { return noQuarterState; }

    const std::shared_ptr<State> &getMState() const { return mState; }

    const std::shared_ptr<State> &getWinnerState() const { return winnerState; }

private:

    int mCount = 0;
    std::shared_ptr<State> hasQuarterState;
    std::shared_ptr<State> soldOutState;
    std::shared_ptr<State> soldState;
    std::shared_ptr<State> noQuarterState;
    std::shared_ptr<State> winnerState;

    std::shared_ptr<State> mState{soldOutState};
};

// GumballState

#endif //DESIGNPATTERN_GUMBALLMACHINE_H
